{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "### VarOr/VarAnd\n",
    "VarOr和VarAnd是演化算法中的两种范式。VarOr表示交叉和变异必须选择其中一种执行。VarAnd则相对自由，可以同时执行交叉和变异，也可以同时不执行它们。GP的原始论文使用的是VarOr。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "8db4ada5ce6ebf73"
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "import numpy as np\n",
    "from deap import base, creator, tools, gp\n",
    "\n",
    "\n",
    "# 符号回归\n",
    "def evalSymbReg(individual, pset):\n",
    "    # 编译GP树为函数\n",
    "    func = gp.compile(expr=individual, pset=pset)\n",
    "\n",
    "    # 使用numpy创建一个向量\n",
    "    x = np.linspace(-10, 10, 100)\n",
    "\n",
    "    # 评估生成的函数并计算MSE\n",
    "    mse = np.mean((func(x) - x ** 2) ** 2)\n",
    "\n",
    "    return (mse,)\n",
    "\n",
    "\n",
    "# 创建个体和适应度函数\n",
    "creator.create(\"FitnessMin\", base.Fitness, weights=(-1.0,))\n",
    "creator.create(\"Individual\", gp.PrimitiveTree, fitness=creator.FitnessMin)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-11-07T08:45:34.512379200Z",
     "start_time": "2023-11-07T08:45:34.394805500Z"
    }
   },
   "id": "initial_id"
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\zhenl\\anaconda3\\Lib\\site-packages\\deap\\gp.py:254: RuntimeWarning: Ephemeral rand101 function cannot be pickled because its generating function is a lambda function. Use functools.partial instead.\n",
      "  warnings.warn(\"Ephemeral {name} function cannot be \"\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "\n",
    "# 定义函数集合和终端集合\n",
    "pset = gp.PrimitiveSet(\"MAIN\", arity=1)\n",
    "pset.addPrimitive(np.add, 2)\n",
    "pset.addPrimitive(np.subtract, 2)\n",
    "pset.addPrimitive(np.multiply, 2)\n",
    "pset.addPrimitive(np.negative, 1)\n",
    "pset.addEphemeralConstant(\"rand101\", lambda: random.randint(-1, 1))\n",
    "pset.renameArguments(ARG0='x')\n",
    "\n",
    "# 定义遗传编程操作\n",
    "toolbox = base.Toolbox()\n",
    "toolbox.register(\"expr\", gp.genHalfAndHalf, pset=pset, min_=1, max_=2)\n",
    "toolbox.register(\"individual\", tools.initIterate, creator.Individual, toolbox.expr)\n",
    "toolbox.register(\"population\", tools.initRepeat, list, toolbox.individual)\n",
    "toolbox.register(\"compile\", gp.compile, pset=pset)\n",
    "toolbox.register(\"evaluate\", evalSymbReg, pset=pset)\n",
    "toolbox.register(\"select\", tools.selTournament, tournsize=3)\n",
    "toolbox.register(\"mate\", gp.cxOnePoint)\n",
    "toolbox.register(\"mutate\", gp.mutUniform, expr=toolbox.expr, pset=pset)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-11-07T08:45:34.526223500Z",
     "start_time": "2023-11-07T08:45:34.514378Z"
    }
   },
   "id": "cb6cf38094256262"
  },
  {
   "cell_type": "markdown",
   "source": [
    "DEAP默认使用VarAnd范式，如果我们想要实现VarOr，就需要自己修改eaSimple函数。当然，具体选择VarAnd还是VarOr要根据具体问题而定。目前尚无统一的结论表明哪种方式一定更好，需要根据问题的特性来决定。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "e09fa8e7890d583b"
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "   \t      \t                       fitness                        \t                      size                     \n",
      "   \t      \t------------------------------------------------------\t-----------------------------------------------\n",
      "gen\tnevals\tavg    \tgen\tmax        \tmin\tnevals\tstd   \tavg    \tgen\tmax\tmin\tnevals\tstd    \n",
      "0  \t300   \t44169.8\t0  \t1.17257e+07\t0  \t300   \t676577\t4.08333\t0  \t7  \t2  \t300   \t1.70774\n",
      "1  \t188   \t3492.82\t1  \t153712     \t0  \t188   \t15171.2\t4.39   \t1  \t13 \t2  \t188   \t2.06347\n",
      "2  \t181   \t2711.47\t2  \t159956     \t0  \t181   \t12524.3\t4.64   \t2  \t18 \t2  \t181   \t2.22345\n",
      "3  \t170   \t5031.11\t3  \t608604     \t0  \t170   \t38065.5\t4.73333\t3  \t13 \t2  \t170   \t2.10449\n",
      "4  \t153   \t8688.17\t4  \t608604     \t0  \t153   \t45093.2\t4.67333\t4  \t13 \t2  \t153   \t2.11502\n",
      "5  \t174   \t86812.5\t5  \t1.23323e+07\t0  \t174   \t991097 \t4.55667\t5  \t15 \t2  \t174   \t2.24354\n",
      "6  \t165   \t3.34976e+06\t6  \t1.00306e+09\t0  \t165   \t5.7815e+07\t4.2    \t6  \t15 \t2  \t165   \t2.15561\n",
      "7  \t174   \t1556.28    \t7  \t159956     \t0  \t174   \t12886.9   \t3.94   \t7  \t11 \t2  \t174   \t1.78225\n",
      "8  \t195   \t3697.63    \t8  \t153712     \t0  \t195   \t21418.5   \t3.92667\t8  \t13 \t3  \t195   \t1.81511\n",
      "9  \t198   \t3854.6     \t9  \t153712     \t0  \t198   \t21463.6   \t3.99667\t9  \t13 \t2  \t198   \t1.823  \n",
      "10 \t172   \t85750.2    \t10 \t1.24839e+07\t0  \t172   \t1.00969e+06\t4      \t10 \t13 \t2  \t172   \t1.83848\n",
      "11 \t184   \t7048.94    \t11 \t153712     \t0  \t184   \t29974.7    \t4.27333\t11 \t11 \t2  \t184   \t1.96094\n",
      "12 \t175   \t2144.17    \t12 \t153712     \t0  \t175   \t15261.8    \t4.04667\t12 \t13 \t2  \t175   \t1.75247\n",
      "13 \t181   \t48966.1    \t13 \t1.23323e+07\t0  \t181   \t711740     \t4.16667\t13 \t13 \t2  \t181   \t1.89707\n",
      "14 \t186   \t168154     \t14 \t1.23323e+07\t0  \t186   \t1.40126e+06\t4.19   \t14 \t15 \t2  \t186   \t1.99514\n",
      "15 \t176   \t3.35003e+06\t15 \t1.00337e+09\t0  \t176   \t5.78324e+07\t4.26333\t15 \t22 \t2  \t176   \t2.18952\n",
      "16 \t191   \t3309.24    \t16 \t159956     \t0  \t191   \t19783.4    \t4.04667\t16 \t13 \t2  \t191   \t1.83607\n",
      "17 \t181   \t4936.87    \t17 \t159956     \t0  \t181   \t24815.9    \t4.07667\t17 \t13 \t2  \t181   \t1.77129\n",
      "18 \t165   \t4943.59    \t18 \t155827     \t0  \t165   \t24763.3    \t3.97333\t18 \t11 \t2  \t165   \t1.60602\n",
      "19 \t188   \t48951.4    \t19 \t1.23323e+07\t0  \t188   \t711103     \t4.05   \t19 \t11 \t2  \t188   \t1.77224\n",
      "20 \t196   \t5683.09    \t20 \t608604     \t0  \t196   \t40442.2    \t3.89667\t20 \t17 \t2  \t196   \t1.87776\n",
      "21 \t173   \t3169.22    \t21 \t153712     \t0  \t173   \t19692.5    \t3.66667\t21 \t9  \t2  \t173   \t1.38884\n",
      "22 \t189   \t4946.32    \t22 \t159956     \t0  \t189   \t24971.6    \t3.80667\t22 \t11 \t2  \t189   \t1.6741 \n",
      "23 \t168   \t1700.25    \t23 \t153712     \t0  \t168   \t12636.3    \t3.62   \t23 \t11 \t2  \t168   \t1.38886\n",
      "24 \t193   \t11328.3    \t24 \t2.42817e+06\t0  \t193   \t141174     \t3.62667\t24 \t9  \t2  \t193   \t1.4026 \n",
      "25 \t188   \t3875.18    \t25 \t625254     \t0  \t188   \t38095      \t3.56667\t25 \t9  \t2  \t188   \t1.32119\n",
      "26 \t186   \t11797      \t26 \t2.42817e+06\t0  \t186   \t141369     \t3.64333\t26 \t10 \t2  \t186   \t1.44319\n",
      "27 \t172   \t44201      \t27 \t1.17257e+07\t0  \t172   \t676066     \t3.73333\t27 \t13 \t2  \t172   \t1.57762\n",
      "28 \t202   \t4998.89    \t28 \t170363     \t0  \t202   \t25280.8    \t3.87   \t28 \t11 \t2  \t202   \t1.59784\n",
      "29 \t172   \t3140.57    \t29 \t159956     \t0  \t172   \t19991.7    \t3.86333\t29 \t13 \t2  \t172   \t1.62008\n",
      "30 \t163   \t41349.6    \t30 \t1.17257e+07\t0  \t163   \t675907     \t3.97333\t30 \t15 \t2  \t163   \t1.89542\n",
      "31 \t179   \t2874.54    \t31 \t157909     \t0  \t179   \t17814.1    \t4      \t31 \t15 \t2  \t179   \t2.00333\n",
      "32 \t179   \t5066.31    \t32 \t608604     \t0  \t179   \t39967.7    \t3.95   \t32 \t13 \t3  \t179   \t1.85315\n",
      "33 \t186   \t46169.8    \t33 \t1.23323e+07\t0  \t186   \t710963     \t4.05667\t33 \t14 \t2  \t186   \t1.89564\n",
      "34 \t173   \t3357.44    \t34 \t159956     \t0  \t173   \t19826      \t3.90667\t34 \t14 \t3  \t173   \t1.85597\n",
      "35 \t193   \t2777.85    \t35 \t159956     \t0  \t193   \t17845.1    \t3.82333\t35 \t11 \t2  \t193   \t1.62033\n",
      "36 \t181   \t84733.5    \t36 \t1.23323e+07\t0  \t181   \t1.00351e+06\t3.8    \t36 \t13 \t2  \t181   \t1.71659\n",
      "37 \t176   \t3150.25    \t37 \t153712     \t0  \t176   \t19627.8    \t3.88333\t37 \t13 \t2  \t176   \t1.67224\n",
      "38 \t190   \t6452.05    \t38 \t159956     \t0  \t190   \t28809.7    \t3.96333\t38 \t13 \t2  \t190   \t1.70548\n",
      "39 \t196   \t3973.32    \t39 \t159956     \t0  \t196   \t21579.2    \t4.07667\t39 \t9  \t2  \t196   \t1.73516\n",
      "40 \t180   \t1619.93    \t40 \t159956     \t0  \t180   \t12847.1    \t3.76333\t40 \t12 \t2  \t180   \t1.54725\n",
      "41 \t174   \t4048.87    \t41 \t159956     \t0  \t174   \t23356.5    \t3.87   \t41 \t10 \t2  \t174   \t1.67723\n",
      "42 \t191   \t1945.1     \t42 \t153712     \t0  \t191   \t12683.5    \t3.86667\t42 \t11 \t2  \t191   \t1.664  \n",
      "43 \t179   \t41841.9    \t43 \t1.14287e+07\t0  \t179   \t658865     \t3.82333\t43 \t11 \t2  \t179   \t1.66697\n",
      "44 \t182   \t4247.9     \t44 \t608604     \t0  \t182   \t38249.9    \t3.82   \t44 \t13 \t2  \t182   \t1.65154\n",
      "45 \t182   \t2844.41    \t45 \t159956     \t0  \t182   \t18048.2    \t3.85   \t45 \t11 \t2  \t182   \t1.68152\n",
      "46 \t191   \t2692.56    \t46 \t153712     \t0  \t191   \t17680.3    \t3.77   \t46 \t12 \t2  \t191   \t1.58864\n",
      "47 \t180   \t40725.5    \t47 \t1.17257e+07\t0  \t180   \t675884     \t3.89667\t47 \t18 \t3  \t180   \t2.02632\n",
      "48 \t181   \t4845.43    \t48 \t614848     \t0  \t181   \t39404.1    \t3.98   \t48 \t11 \t2  \t181   \t1.81281\n",
      "49 \t176   \t43922.1    \t49 \t1.17257e+07\t0  \t176   \t676718     \t3.89667\t49 \t13 \t2  \t176   \t1.76238\n",
      "50 \t157   \t43799.4    \t50 \t1.23323e+07\t0  \t157   \t710885     \t3.97333\t50 \t12 \t2  \t157   \t1.81823\n",
      "time: 0.834498405456543\n",
      "multiply(x, x)\n"
     ]
    }
   ],
   "source": [
    "from deap.algorithms import varOr\n",
    "import numpy\n",
    "from deap import algorithms\n",
    "\n",
    "\n",
    "def eaSimple(population, toolbox, cxpb, mutpb, ngen, stats=None,\n",
    "             halloffame=None, verbose=__debug__):\n",
    "    logbook = tools.Logbook()\n",
    "    logbook.header = ['gen', 'nevals'] + (stats.fields if stats else [])\n",
    "\n",
    "    # Evaluate the individuals with an invalid fitness\n",
    "    invalid_ind = [ind for ind in population if not ind.fitness.valid]\n",
    "    fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)\n",
    "    for ind, fit in zip(invalid_ind, fitnesses):\n",
    "        ind.fitness.values = fit\n",
    "\n",
    "    if halloffame is not None:\n",
    "        halloffame.update(population)\n",
    "\n",
    "    record = stats.compile(population) if stats else {}\n",
    "    logbook.record(gen=0, nevals=len(invalid_ind), **record)\n",
    "    if verbose:\n",
    "        print(logbook.stream)\n",
    "\n",
    "    # Begin the generational process\n",
    "    for gen in range(1, ngen + 1):\n",
    "        # Select the next generation individuals\n",
    "        offspring = toolbox.select(population, len(population))\n",
    "\n",
    "        # Vary the pool of individuals\n",
    "        offspring = varOr(offspring, toolbox, len(offspring),cxpb, mutpb)\n",
    "\n",
    "        # Evaluate the individuals with an invalid fitness\n",
    "        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]\n",
    "        fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)\n",
    "        for ind, fit in zip(invalid_ind, fitnesses):\n",
    "            ind.fitness.values = fit\n",
    "\n",
    "        # Update the hall of fame with the generated individuals\n",
    "        if halloffame is not None:\n",
    "            halloffame.update(offspring)\n",
    "\n",
    "        # Replace the current population by the offspring\n",
    "        population[:] = offspring\n",
    "\n",
    "        # Append the current generation statistics to the logbook\n",
    "        record = stats.compile(population) if stats else {}\n",
    "        logbook.record(gen=gen, nevals=len(invalid_ind), **record)\n",
    "        if verbose:\n",
    "            print(logbook.stream)\n",
    "\n",
    "    return population, logbook\n",
    "\n",
    "\n",
    "# 定义统计指标\n",
    "stats_fit = tools.Statistics(lambda ind: ind.fitness.values)\n",
    "stats_size = tools.Statistics(len)\n",
    "mstats = tools.MultiStatistics(fitness=stats_fit, size=stats_size)\n",
    "mstats.register(\"avg\", numpy.mean)\n",
    "mstats.register(\"std\", numpy.std)\n",
    "mstats.register(\"min\", numpy.min)\n",
    "mstats.register(\"max\", numpy.max)\n",
    "\n",
    "# 使用默认算法\n",
    "start = time.time()\n",
    "population = toolbox.population(n=300)\n",
    "hof = tools.HallOfFame(1)\n",
    "pop, log = algorithms.eaSimple(population=population,\n",
    "                               toolbox=toolbox, cxpb=0.5, mutpb=0.2, ngen=50, stats=mstats, halloffame=hof,\n",
    "                               verbose=True)\n",
    "end = time.time()\n",
    "print('time:', end - start)\n",
    "print(str(hof[0]))"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-11-07T08:45:35.379380400Z",
     "start_time": "2023-11-07T08:45:34.528223800Z"
    }
   },
   "id": "88c62bc071d56191"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
